package com.kuang.single;

// 懒汉模式
public class LazyMan {

    private static LazyMan LazyMan;

    public LazyMan() {
        System.out.println(Thread.currentThread().getName() + "ok");
    }

    public static LazyMan lazyMan;

    // 双重检测锁+volatile禁止指令重排操作
    public static volatile LazyMan lazyMan1;


    public static LazyMan getInstance1(){
        if (lazyMan == null){
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }

    // 双重检测锁模式  懒汉单例模式 DCL懒汉式
    // 双层锁模式，实现效果：多线程并发情况下，只有一个线程获取到实例
    public static LazyMan getInstance2(){
        if (lazyMan == null){
            synchronized (LazyMan.class){
                if (lazyMan == null){
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }

    // 双重检测锁+volatile禁止指令重排操作：保证避免指令重排，来确保原子性操作
    public static LazyMan getInstance3(){
        if (lazyMan1 == null){
            synchronized (LazyMan.class){
                if (lazyMan1 == null){
                    lazyMan1 = new LazyMan();
                }
            }
        }
        return lazyMan1;
    }


    // 多线程并发测试
    public static void main(String[] args) {
        // 多个线程获取实例，判断获取到的实例是否同一个
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                LazyMan.getInstance3();
            }).start();
        }
    }

    /*
        Thread-0ok  打印输出了多个线程，构造了多个实例，所以加双层检测模式
        Thread-4ok
        Thread-3ok
        Thread-6ok
        Thread-1ok
     */

    /*
        Thread-0ok  双层检测模式，实现效果：多线程并发情况下，只有一个线程获取到实例
                    但是这样可能会有指令重排问题，因为 new LazyMan() 不是一个原子操作
                    里面操作多个步骤：
                        1.分配内存空间
                        2.执行构造器房费，初始化对象
                        3.把这个对象指向这个空间
                    双重检测锁+volatile禁止指令重排操作：保证避免指令重排，来确保原子性操作
     */

    /*
        Thread-0ok  双重检测锁+volatile禁止指令重排操作 最终实现了单例模式
     */

}
